#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include <cctype>
using namespace std;

// DICTIONARIES 字典
const int KEY_DICTIONARY_LEN = 56;
const int SPLIT_DICTIONARY_LEN = 13;
const int OPERATOR_DICTIONARY_LEN = 35;
const string KEY_DICTIONARY[KEY_DICTIONARY_LEN]={"cin","cout","include","define","using","namespace","std","const","endl","volatile","goto","class","public","private","protected","friend","this","template","inline","virtual","new","delete","operator","try","catch","throw","int","double","float","long","bool","char","signed","unsigned","struct","enum","union","mutable","true","false","continue","break","for","while","do","switch","case","default","if","else","return","auto","register","extern","sizeof","typedef"};
const char SPLIT_DICTIONARY[SPLIT_DICTIONARY_LEN]={'[', ']', '{', '}', '(', ')', ';', ',', '#', ':','?'};
const string OPERATOR_DICTIONARY[OPERATOR_DICTIONARY_LEN]={"+","-","*","%","/","++","--",".","==","!=",">","<",">=","<=","&&","||","!","&","|","^","~","<<",">>","=","+=","-=","*=","/=","%=","<<=",">>=","&=","^=","|=","->"};

string append_char(string str,char c){
    char char_str[2];
    char_str[0]=c;
    char_str[1]='\0';
    str=str+char_str;
    return str;
}

// 标识符过滤器
bool filter_sign(string original,char add_char){
    if(original==""){ // 作为首字符
        return (isalpha(add_char)||add_char=='_');
    }else{
        return (isalnum(add_char)||add_char=='_');
    }
}
// 关键字过滤器
bool filter_key(string original,char add_char){
    if(!isalpha(add_char)) return false;
    string test_str = append_char(original,add_char);
    int find_index = 0;
    for(int i=0;i<KEY_DICTIONARY_LEN;i++){
        find_index = KEY_DICTIONARY[i].find(test_str);
        if(find_index==0){
            return true;
        }
    }
    return false;
}
// 数字过滤器
bool filter_number(string original,char add_char){ // 1, 1.5
    if(original=="") return isdigit(add_char)||add_char=='-';
    if(original[0]=='-' && original.length()==1) return isdigit(add_char);
    return isdigit(add_char)||add_char=='.'||add_char=='e'||add_char=='E'||add_char=='+'||add_char=='-';
}
// 字符串过滤器
bool filter_string(string original,char add_char){
    if(original=="") return add_char=='"';
    else if (original[original.length()-1]=='"' && original.length()>1)return false;
    else return true;
}
// 注释过滤器
bool filter_commented_out(string original,char add_char){ // 支持//
    if(original.length()==0) return add_char=='/';
    if(original.length()==1) return add_char=='/'||add_char=='*';
    if(original[original.length()-2]=='*' && original[original.length()-1]=='/') return false;
    return true;
}
// 分界符过滤器
bool filter_split(string original,char add_char){
    if(original==""){
        for(int i=0;i<SPLIT_DICTIONARY_LEN;i++){
            if(add_char==SPLIT_DICTIONARY[i]) return true;
        }
    }
    return false;
}
// 运算符过滤器
bool filter_operator(string original,char add_char){
    string test_str = append_char(original,add_char);
    for(int i=0;i<OPERATOR_DICTIONARY_LEN;i++){
        if(OPERATOR_DICTIONARY[i].find(test_str)==0)return true;
    }
    return false;

}

int scan_btns(bool* arr, int length){
    int on_btns=0;
    for(int i=0;i<length;i++) on_btns += (arr[i]?1:0);
    return on_btns;
}

int main()
{
    char filePath[100];
    bool model = false;// true:默认,false:自定义输入文件
    cout<<"SCNU_20142100016 郑志成 词法分析程序"<<endl;
    cout<<"[0:默认测试;1:自定义输入文件测试]:";
    cin>>model;cin.get();
    if(model==1){
        cout<<"文件路径:";
        cin.getline(filePath,100);
    }else strcpy(filePath,"demo.cpp");

    ifstream file;
    file.open(filePath,ios::in);


    // 打开失败
    if(!file.is_open()){
        cout<<"failed to open file " << filePath<<endl;
        cout<<"process any key to quit";
        cin.get();
        return 0;
    }
    cout<<"--- "<<filePath<<" is opened ---"<<endl;

    // 0 标识符
    // 1 关键字
    // 2 数
    // 3 字符串
    // 4 注释
    // 5 分界符/特殊符号
    // 6 运算符号
    const int BUTTONS_LENGTH = 7;
    bool buttons[BUTTONS_LENGTH];
    string types[7]={"标识符","关键字","数","字符串","注释","分界符","运算符"};
    int last_filter = 0;
    for(int i=0;i<BUTTONS_LENGTH;i++) buttons[i]=true;

    // 配置过滤器组件
    bool (*filter[BUTTONS_LENGTH])(string original,char add_char);
    filter[0]=filter_sign;
    filter[1]=filter_key;
    filter[2]=filter_number;
    filter[3]=filter_string;
    filter[4]=filter_commented_out;
    filter[5]=filter_split;
    filter[6]=filter_operator;

    string code_per_line,in_buff,out_buff;
    int line_length,on_btns;
    char new_pipe_char;

    // 核心：过滤器工艺的流水线处理
    while(getline(file,code_per_line)){
        // 逐行处理
        line_length=code_per_line.length();
        if(line_length==0) continue; // 跳过空行

        in_buff="",out_buff="";          // 输入、输出缓冲
        on_btns = 0;                     // 打开了的过滤器数
        new_pipe_char = code_per_line[0];// 新投料
        for(int t=0;t<BUTTONS_LENGTH;t++) buttons[t]=true; // 过滤器开关

        // 每次只投料一个进入到流水线中
        for(int i=0;i<line_length;){
            for(int btn_index=0;btn_index<BUTTONS_LENGTH;btn_index++){          // 通过过滤器组件
                if(buttons[btn_index]){
                    buttons[btn_index]=filter[btn_index](in_buff,new_pipe_char);
                    last_filter = btn_index;
                }
            }
            on_btns = scan_btns(buttons,BUTTONS_LENGTH);
            // 根据剩余有效过滤器进行分流处理：
            // 0: 输出缓冲中恰好组成某一个类"单词"
            // >0:缓冲可继续吸纳
            if(on_btns==0){
                for(int t=0;t<BUTTONS_LENGTH;t++) buttons[t]=true;
                if(out_buff!=""){
                    switch(last_filter){
                        case 1:{
                            bool flag=false;
                            for(int j=0;j<KEY_DICTIONARY_LEN;j++){
                                if(KEY_DICTIONARY[j]==out_buff) flag=true;
                            };
                            cout<<out_buff<<'\t'<<types[flag]<<endl;
                            break;
                        }
                        default:cout<<out_buff<<'\t'<<types[last_filter]<<endl;
                    }
                    out_buff=in_buff="";
                    continue;
                }
            }else if(on_btns>0){
                char pipe_release[2];               // 新成功投料字符
                pipe_release[0]=new_pipe_char;
                pipe_release[1]='\0';
                out_buff = out_buff+pipe_release;   // 添加到输出缓冲、输入缓冲中
                in_buff = in_buff+pipe_release;
            }
            // 获取吸取下一个字符进入流水线处理，并处理一些行末逻辑
            new_pipe_char = code_per_line[++i];
            if(i==line_length&&out_buff!=""){
              for(int j=0;j<BUTTONS_LENGTH;j++){
                if(buttons[j])
                    cout<< out_buff <<'\t'<<types[j]<<endl;
              }
            }
        } // walk code_per_length for each char

    }// end while,walk the file

    file.close();
    cout<<"[tips]thanks using!enter any key to quit";
    cin.get();
    return 0;
}
